package com.zgs.androidopengl.util

import android.opengl.GLES20.GL_COMPILE_STATUS
import android.opengl.GLES20.GL_FRAGMENT_SHADER
import android.opengl.GLES20.GL_LINK_STATUS
import android.opengl.GLES20.GL_VERTEX_SHADER
import android.opengl.GLES20.glAttachShader
import android.opengl.GLES20.glCompileShader
import android.opengl.GLES20.glCreateProgram
import android.opengl.GLES20.glCreateShader
import android.opengl.GLES20.glDeleteProgram
import android.opengl.GLES20.glDeleteShader
import android.opengl.GLES20.glGetProgramInfoLog
import android.opengl.GLES20.glGetProgramiv
import android.opengl.GLES20.glGetShaderInfoLog
import android.opengl.GLES20.glGetShaderiv
import android.opengl.GLES20.glLinkProgram
import android.opengl.GLES20.glShaderSource
import android.opengl.GLES20.glValidateProgram
import android.util.Log

object ShaderHelp {

    const val TAG = "ShaderHelp"

    fun compileVertexShader(shader: String?): Int {
        return compileShader(GL_VERTEX_SHADER, shader)
    }

    fun compileFragmentShader(shader: String?): Int {
        return compileShader(GL_FRAGMENT_SHADER, shader)
    }

    private fun compileShader(type: Int, shaderCode: String?): Int {
        val shaderObjectId = glCreateShader(type)
        if (shaderObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.e(TAG, "Could not create new shader.")
            }
            return 0
        }

        glShaderSource(shaderObjectId, shaderCode)
        glCompileShader(shaderObjectId)

        val compileStatus = IntArray(1)
        glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0)

        if (LoggerConfig.ON) {
            Log.v(
                TAG,
                "Results of compiling source:" + "\n" + shaderCode + "\n:" + glGetShaderInfoLog(
                    shaderObjectId
                )
            )
        }

        if (compileStatus[0] == 0) {
            //相当于如果失败了，就删除这个gl shader object
            glDeleteShader(shaderObjectId)
            if (LoggerConfig.ON) {
                Log.e(TAG, "Compilation of shader failed.")
            }
            return 0
        }


        return shaderObjectId
    }

    fun linkProgram(vertexShaderId: Int, fragmentShaderId: Int): Int {
        val programObjectId = glCreateProgram()
        if (programObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.e(TAG, "Could not create new program.")
            }
            return 0
        }
        //使用glAttachShader把顶点着色器和片段着色器关联到程序对象上
        glAttachShader(programObjectId, vertexShaderId)
        glAttachShader(programObjectId, fragmentShaderId)

        //链接到程序对象上
        glLinkProgram(programObjectId)
        val linkStatus = IntArray(1)

        glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0)

        if (LoggerConfig.ON) {
            Log.v(
                TAG,
                "Results of linking program:\n" + glGetProgramInfoLog(programObjectId)
            )
        }

        if (linkStatus[0] == 0) {
            glDeleteProgram(programObjectId)
            if (LoggerConfig.ON) {
                Log.e(TAG, "Linking of program failed.")
            }
            return 0
        }

        return programObjectId
    }

    fun validateProgram(programObjectId: Int): Boolean {
        glValidateProgram(programObjectId)

        val validateStatus = IntArray(1)
        glGetProgramiv(programObjectId, GL_COMPILE_STATUS, validateStatus, 0)

        Log.v(
            TAG,
            "Results of validating program:\n" + glGetProgramInfoLog(programObjectId)
        )
        return validateStatus[0] != 0
    }
}